"""
音频处理工具函数
"""
import librosa
import soundfile as sf
import io
import tempfile
import os
from typing import Tuple, Optional
from fastapi import UploadFile

from app.core.exceptions import AudioProcessingException, FileSizeExceededException


def validate_audio_file(file: UploadFile, max_size: int) -> None:
    """
    验证音频文件
    
    Args:
        file: 上传的文件
        max_size: 最大文件大小（字节）
    
    Raises:
        FileSizeExceededException: 文件过大
        AudioProcessingException: 不支持的文件类型
    """
    # 检查文件大小
    file_size = len(file.file.read())
    file.file.seek(0)  # 重置文件指针
    
    if file_size > max_size:
        raise FileSizeExceededException(max_size)
    
    # 检查文件类型
    if not file.content_type or not file.content_type.startswith('audio/'):
        raise AudioProcessingException("不支持的文件类型，请上传音频文件")


def process_audio_pitch_shift(
    audio_data: bytes, 
    n_steps: int,
    input_format: str = "WAV"
) -> Tuple[bytes, int]:
    """
    处理音频音调调节
    
    Args:
        audio_data: 音频文件的字节数据
        n_steps: 音调调节的半音数，正数升高，负数降低
        input_format: 输入格式
    
    Returns:
        Tuple[bytes, int]: 处理后的音频字节数据和采样率
    
    Raises:
        AudioProcessingException: 音频处理失败
    """
    try:
        # 使用临时文件处理音频数据
        with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as temp_input:
            temp_input.write(audio_data)
            temp_input.flush()
            
            try:
                # 加载音频文件
                y, sr = librosa.load(temp_input.name, sr=None)
                
                # 进行音调调节
                y_shifted = librosa.effects.pitch_shift(y, sr=sr, n_steps=n_steps)
                
                # 将处理后的音频保存到内存
                with io.BytesIO() as output_buffer:
                    sf.write(output_buffer, y_shifted, sr, format='WAV')
                    output_buffer.seek(0)
                    return output_buffer.getvalue(), sr
                    
            finally:
                # 清理临时文件
                try:
                    os.unlink(temp_input.name)
                except:
                    pass
                    
    except Exception as e:
        raise AudioProcessingException(f"音频处理失败: {str(e)}")


def get_audio_info(audio_data: bytes) -> dict:
    """
    获取音频文件信息
    
    Args:
        audio_data: 音频文件的字节数据
    
    Returns:
        dict: 音频信息包含采样率、时长等
    """
    try:
        with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as temp_file:
            temp_file.write(audio_data)
            temp_file.flush()
            
            try:
                y, sr = librosa.load(temp_file.name, sr=None)
                duration = len(y) / sr
                
                return {
                    "sample_rate": sr,
                    "duration": duration,
                    "channels": 1 if len(y.shape) == 1 else y.shape[1],
                    "samples": len(y)
                }
            finally:
                try:
                    os.unlink(temp_file.name)
                except:
                    pass
                    
    except Exception as e:
        raise AudioProcessingException(f"获取音频信息失败: {str(e)}")


def format_processing_time(seconds: float) -> str:
    """
    格式化处理时间显示
    
    Args:
        seconds: 处理时间（秒）
    
    Returns:
        str: 格式化的时间字符串
    """
    if seconds < 1:
        return f"{seconds*1000:.1f}ms"
    elif seconds < 60:
        return f"{seconds:.2f}s"
    else:
        minutes = int(seconds // 60)
        remaining_seconds = seconds % 60
        return f"{minutes}m {remaining_seconds:.1f}s"
